import { createApp, createRenderer, h } from "vue";
import App from "./App.vue";
import CanvasApp from "./CanvasApp.vue";
import EditTodo from "@/components/todos/EditTodo.vue";
import "./registerServiceWorker";
import router from "./router";
import store from "./store";

// Global API 改为应用程序实例调用 同时 h 渲染函数 额外提出来了
// [全局 API](https://v3.cn.vuejs.org/guide/migration/global-api.html#全局-api)
createApp(App)
  .component("comp1", () => "I am comp2 define on the App instance")
  .component("comp2", {
    render() {
      return h("div", "I am comp2 define on the App instance");
    },
  })
  .component("EditTodo", EditTodo)
  // 设置完这个指令有一个高亮的效果
  .directive("heighlight", {
    beforeMount(el, binding, vnode) {
      el.style.background = binding.value;
    },
  })
  .use(store)
  .use(router)
  .mount("#app");

const draw = (el, noClear) => {
  if (!noClear) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  }
  if (el.tag == "piechart") {
    let { data, r, x, y } = el;
    let total = data.reduce((memo, current) => memo + current.count, 0);
    let start = 0,
      end = 0;
    data.forEach((item) => {
      end += (item.count / total) * 360;
      drawPieChart(start, end, item.color, x, y, r);
      drawPieChartText(item.name, (start + end) / 2, x, y, r);
      start = end;
    });
  }
  el.childs && el.childs.forEach((child) => draw(child, true));
};

const d2a = (n) => {
  return (n * Math.PI) / 180;
};
const drawPieChart = (start, end, color, cx, cy, r) => {
  let x = cx + Math.cos(d2a(start)) * r;
  let y = cy + Math.sin(d2a(start)) * r;
  ctx.beginPath();
  ctx.moveTo(cx, cy);
  ctx.lineTo(x, y);
  ctx.arc(cx, cy, r, d2a(start), d2a(end), false);
  ctx.fillStyle = color;
  ctx.fill();
  ctx.stroke();
  ctx.closePath();
};
const drawPieChartText = (val, position, cx, cy, r) => {
  ctx.beginPath();
  let x = cx + (Math.cos(d2a(position)) * r) / 1.25 - 20;
  let y = cy + (Math.sin(d2a(position)) * r) / 1.25;
  ctx.fillStyle = "#000";
  ctx.font = "20px 微软雅黑";
  ctx.fillText(val, x, y);
  ctx.closePath();
};

// 自定义渲染器
const renderer = createRenderer({
  // 运行时间遭早于insert
  patchProp(el, key, prevValue, nextValue) {
    // 属性更新
    el[key] = nextValue;
  },
  insert(child, parent, anchor) {
    // 处理元素插入逻辑
    // child.parent = parent; // 让子元素有一个父元素

    if (!parent.childs) {
      // 父元素没有一个子元素的数组对象，那就创建一个并保存子元素进去
      parent.childs = [child];
    } else {
      // 假如父元素有一个子元素的数组属性，说明此时不是初始化了，我们经子元素推入这个父节点
      parent.childs.push(child);
    }
    // 2. 如果是真实的 dom 元素，在这里会是Canvas，需要绘制
    if (parent.nodeType == 1) {
      draw(child);
      // 额外处理事件
      if (child.onClick) {
        ctx.canvas.addEventListener("click", () => {
          child.onClick();
          setTimeout(() => {
            draw(child);
          }, 0);
        });
      }
    }
  },
  remove: (child) => {},
  // 创建虚拟节点【类似于节点的数据机构存在于内存中，是json树】
  createElement(tag, isSVG, is) {
    // 处理元素创建逻辑
    return { tag };
  },
  createText: (text) => {},
  createComment: (text) => {},
  setText: (node, text) => {},
  setElementText: (el, text) => {},
  parentNode: (node) => {},
  nextSibling: (node) => {},
  querySelector: (selector) => {},
  setScopeId(el, id) {},
  cloneNode(el) {},
  insertStaticContent(content, parent, anchor, isSVG) {},
});

let ctx, canvas;

// 扩展mount，首先创建一个画布元素
function createCanvasApp(App) {
  const app = renderer.createApp(App);
  const mount = app.mount;
  app.mount = function (selector) {
    canvas = document.createElement("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    document.querySelector(selector).appendChild(canvas);
    ctx = canvas.getContext("2d");
    mount(canvas);
  };
  return app;
}

// 关闭自定义渲染器因为总是爆一个 backend.js 的错误
// createCanvasApp(CanvasApp).mount("#demo");
